//-------------------------------------------------------------------
//	Copyright (c) 2010-2011  Zhirnov Andrey
//	This file is part of the "UXGEN_ResourceConverter" project.
//	See copyright notice in "Converter.h".
//-------------------------------------------------------------------

#ifndef _RC_MESH_CONVERTERS_H
#define _RC_MESH_CONVERTERS_H

#include "stdafx.h"


//
// Model Data
//

struct TModelData
{
	// types
	struct TModelMesh
	{
		string			sName;
		TMesh			sMesh;
		uint			uAnimationIdx,
						uMaterialIdx,
						uPhysicsIdx;
		///
		TModelMesh(const char *name = nullptr): sName(name), uAnimationIdx(-1), uMaterialIdx(-1), uPhysicsIdx(-1) {}
	};

	struct TMeshAnimInfo
	{
		string			sName;
		TMeshAnimation	sAnim;
		///
		TMeshAnimInfo(const char *name = nullptr): sName(name) {}
	};

	struct TMeshMtrInfo
	{
		string			sName;
		TMeshMaterial	sMaterial;
		///
		TMeshMtrInfo(const char *name = nullptr): sName(name) {}
	};

	struct TMeshPhysInfo
	{
		string			sName;
		TMeshPhysics	sPhys;
		///
		TMeshPhysInfo(const char *name = nullptr): sName(name) {}
	};


	// values
	array< TModelMesh >			aMeshes;
	array< TMeshAnimInfo >		aAnimations;
	array< TMeshMtrInfo >		aMaterials;
	array< TMeshPhysInfo >		aPhysics;
	///
	TModelData() {}

	void Clear()
	{
		aMeshes.Clear();
		aAnimations.Clear();
		aMaterials.Clear();
		aPhysics.Clear();
	}
};


//
// Model Convert Info
//

struct TModelInfo
{
	// in
	const char *		pFileName;
	const string	&	sMtrPath;
	const string	&	sTexPath;
	E_MODEL_COMPONENT	eLoadType;
	E_MODEL_FLAGS		eModelFlags;
	// out
	TModelData		&	sData;
	///
	TModelInfo(const char *file, E_MODEL_COMPONENT load_type, E_MODEL_FLAGS flags, TModelData &data,
				const string &mtr_path, const string &tex_path):
		pFileName(file), eLoadType(load_type), sData(data), eModelFlags(flags), sMtrPath(mtr_path), sTexPath(tex_path)
	{}
};


//
// Vertex Attribute Link
//

struct TVertAttribLink
{
	gl_vertex::type			eType;
	e_vertex_attrib::type	eLocation;
	float					fScale;
	bool					bNormalize		: 1;
	bool					bNormalized		: 1;
	bool					bScale			: 1;
	bool					bDisabled		: 1;
	///
	TVertAttribLink():
		eType(gl_vertex::_INIT), eLocation(e_vertex_attrib::UNKNOWN), fScale(0.f),
		bNormalize(false), bNormalized(false), bScale(false), bDisabled(false)
	{}
};


//
// GL Render State
//

struct TGLRenderState
{
	// blending //
	gl_blend_func::type		eSrcRGB,
							eSrcAlpha,
							eDstRGB,
							eDstAlpha;
	gl_blend_equation::type	eModeRGB,
							eModeAlpha;
	e_color_mask::type		eColorMask;
	bool					bBlending;

	// depth //
	gl_compare_mode::type	eDepthFunc;
	bool					bDepthWrite;
	bool					bDepthTest;

	// stencil //
	gl_compare_mode::type	eStencilFunc;
	int						iStencilFuncRef;
	uint					uStencilFuncMask;
	uint					uStencilMask;
	bool					bStencilTest;

	// culling //
	e_cull_mode::type		eCullMode;

	///
	TGLRenderState():
		eSrcRGB(gl_blend_func::ONE),			eSrcAlpha(gl_blend_func::ONE),
		eDstRGB(gl_blend_func::ZERO),			eDstAlpha(gl_blend_func::ZERO),
		eModeRGB(gl_blend_equation::ADD),		eModeAlpha(gl_blend_equation::ADD),
		eColorMask(e_color_mask::RGBA),			eDepthFunc(gl_compare_mode::LEQUAL),
		bDepthWrite(true),						bDepthTest(true),
		eStencilFunc(gl_compare_mode::EQUAL),	bStencilTest(false),
		uStencilMask(1),						bBlending(false),
		eCullMode(e_cull_mode::DEFAULT),		iStencilFuncRef(0),
		uStencilFuncMask(1)
		{}
};


//
// Material
//

struct TMaterial
{
	// types
	struct TMaterialLayer
	{
		string		sMapFileName;
		color4f		sColor;
		///
		TMaterialLayer() {}
		TMaterialLayer(const char *name, const color4f &color): sMapFileName(name), sColor(color) {}
		TMaterialLayer(const string &name, const color4f &color): sMapFileName(name), sColor(color) {}
	};

	// values
	string			sName;
	TGLRenderState	sStates;
	TMaterialLayer	sDiffuse,
					sSpecular,
					sEmission,
					sAmbient;
	string			sNormalMap,
					sHeightMap,
					sOpacityMap,
					sReflectionMap;
	float			fShininess,
					fOpacity;
	bool			bRSEnabled;

	// constructor
	TMaterial(): fShininess(0.f), fOpacity(0.f), bRSEnabled(false) {}
};



// Optimization and repacking vertices //
bool OptimizeVertices(TMesh &sMesh, const float fAccuracy, E_MESH_VERT_PACK ePackType);
bool OptimizeIndices(TMesh &sMesh, const uint uCashSize);

// Utils //
bool SceletalMeshToMultiMesh(TMesh &sMesh, const TMeshAnimation &sAnim, const uint32_array_t &aTracks);
bool GenerateTBN(TMesh &sMesh, bool bTangent, bool bBinormal, bool bNormal);
bool ChangeVertexAttribs(TMesh &sMesh, const array<TMeshVertices> &aAttribs);
bool CalculateBBoxes(TMesh &sMesh);
bool CalculateTrackBBoxes(const TSceletalMesh &sMesh, TSceletalAnimData &sAnim);

// Helper functions //
uint GetVertexSize(gl_vertex::type eType);
uint GetIndexSize(gl_index::type eType);

// Convert Material //
bool SaveMaterial(const string &sFileName, const TMaterial &sMtr);


class IGeometryConverter
{
public:
	virtual ~IGeometryConverter() {}
	virtual bool ConvertMesh(TModelInfo &) = 0;
	virtual bool ConvertFrameAnim(TModelInfo &) = 0;
	virtual bool ConvertSceletal(TModelInfo &) = 0;
	//virtual bool ConvertMorphing(TModelInfo &) = 0;
	//virtual bool ConvertTransform(TModelInfo &) = 0;
	//virtual bool ConvertScene(TModelInfo &) = 0;
	virtual bool ConvertAutoType(TModelInfo &) = 0;
};


// COLLADA //
class CColladaConverter : public IGeometryConverter
{
public:
	virtual bool ConvertMesh(TModelInfo &sInfo);
	virtual bool ConvertFrameAnim(TModelInfo &sInfo);
	virtual bool ConvertSceletal(TModelInfo &sInfo);
	virtual bool ConvertAutoType(TModelInfo &sInfo);
};


// 3DS //
class C3DSConverter : public IGeometryConverter
{
public:
	virtual bool ConvertMesh(TModelInfo &sInfo);
	virtual bool ConvertFrameAnim(TModelInfo &sInfo);
	virtual bool ConvertSceletal(TModelInfo &sInfo);
	virtual bool ConvertAutoType(TModelInfo &sInfo);
};


// MD5 //
class CMD5Converter : public IGeometryConverter
{
public:
	virtual bool ConvertMesh(TModelInfo &sInfo);
	virtual bool ConvertFrameAnim(TModelInfo &sInfo);
	virtual bool ConvertSceletal(TModelInfo &sInfo);
	virtual bool ConvertAutoType(TModelInfo &sInfo);
};


// DMD //
class CDMDConverter : public IGeometryConverter
{
public:
	virtual bool ConvertMesh(TModelInfo &sInfo);
	virtual bool ConvertFrameAnim(TModelInfo &sInfo);
	virtual bool ConvertSceletal(TModelInfo &sInfo);
	virtual bool ConvertAutoType(TModelInfo &sInfo);
};


// OBJ //
class COBJConverter : public IGeometryConverter
{
public:
	virtual bool ConvertMesh(TModelInfo &sInfo);
	virtual bool ConvertFrameAnim(TModelInfo &sInfo);
	virtual bool ConvertSceletal(TModelInfo &sInfo);
	virtual bool ConvertAutoType(TModelInfo &sInfo);
};


// MDL (UXGEN) //
class CMDLConverter : public IGeometryConverter
{
public:
	virtual bool ConvertMesh(TModelInfo &sInfo);
	virtual bool ConvertFrameAnim(TModelInfo &sInfo);
	virtual bool ConvertSceletal(TModelInfo &sInfo);
	virtual bool ConvertAutoType(TModelInfo &sInfo);
};


#endif	// _RC_MESH_CONVERTERS_H